home *** CD-ROM | disk | FTP | other *** search
Text File | 1986-05-16 | 132.9 KB | 2,929 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A GUIDE TO THE PC-LISP INTERPRETER (V2.11)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- By Peter Ashwood-Smith
- ~~~~~~~~~~~~~~~~~~~~~~
-
- University of Toronto,
- ~~~~~~~~~~~~~~~~~~~~~
-
- Ontario, Canada.
- ~~~~~~~~~~~~~~~
-
-
-
-
- With thanks to Brian Robertson for the math functions
-
-
-
- May 15 1986,
-
-
- for Guylaine
-
-
- email: petera!utcsri or br!utcsri
-
- mail: Peter Ashwood-Smith
- #811, 120 St. Patrick St.
- Toronto, Ontario,
- Canada,
- M5T-2X7.
-
- phone: (416) 593-7574.
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
- INTRODUCTION
- ~~~~~~~~~~~~
- PC-LISP is a small implementation of LISP for ANY MS-DOS
- machine. While small, it is capable of running a pretty good
- subset of Franz LISP. The functions are supposed to perform in
- the same way as Franz with a few exceptions made for effeciencies
- sake. Version 2.11 has the following features.
-
- - Types fixnum, flonum, list, port, symbol, string and
- hunk, lambda, nlambda, macro and lexpr.
-
- - Read Macros including splicing read macros.
-
- - Full garbage collection of ALL types.
-
- - Compacting relocating heap management.
-
- - Access to some MSDOS BIOS graphics routines.
-
- - Over 150 built in functions, sufficient to allow you
- to implement many other Franz functions in PC-LISP.
-
- - Stack overflow detection & full error checking
- on all calls, tracing of user defined functions,
- and dumping of stack via (showstack).
-
- - One level of break from which bindings at point
- of error can be seen.
-
- - Access to as much (non extended) memory as you've
- got and control over how this memory is spread
- among the various data types.
-
- - Will run on 256K PC/AT(w/woEGA)/XT and just about any
- other MS-DOS machine. It is not hardware dependent.
-
- This program is Shareware. This means that it you are free
- to distribute it or post it to any BBS that you want. The more
- the better. The idea is that if you feel you like the program and
- are pleased with it then send us $15 to help cover development
- costs. Source code for this program is available upon request.
- You must however send me 3 blank diskettes and about $1.50 to
- cover first class postage. The program can be compiled with any
- good C compiler that has a pretty complete libc. In particular
- the program will compile with almost no changes on most Unix
- systems. A source code guide will probably be included with the
- source if it is finished at the time I receive your source
- request. Please do not request source unless you plan to use it.
-
- Thanks to Brian Robertson also of the University of Toronto
- Department of Computer Science for the math functions that he
- wrote for the otherwise excellent Lattice C V2.03 compiler which
- did not originally come with a math library.
-
-
-
-
- 2
-
-
-
- A WARNING
- ~~~~~~~~~
- As I mentioned previously this program was compiled with the
- Lattice C compiler, as such the program contains code to which
- Lattice Inc. holds a copyright. If you sell it I can only get
- angry but Lattice could take you to court. And, as with all
- software, you use it at your own risk. I will not be held
- responsible for loss of any kind as a result of the correct or
- incorrect use of this program.
-
- A NOTE
- ~~~~~~
- The rest of this manual assumes some knowledge of LISP,
- MSDOS and a little programming experience. If you are new to LISP
- or programming in general you should work your way through a book
- on LISP such as LISPcraft by Robert Wilensky. You can use the
- interpreter to run almost all of the examples in the earlier
- chapters. I obviously cannot attempt to teach you LISP here
- because it would require many hundreds of pages and there are
- much better books on the subject than I could write. Also, there
- are other good books on Franz LISP besides LISPcraft. I recommend
- LISPcraft because it is the book I happen to use.
-
- IF YOU WANT TO TRY PC-LISP RIGHT NOW
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Make sure that PC-LISP.EXE and PC-LISP.L are in the same
- directory. Then type PC-LISP from the DOS prompt. Wait until you
- get the "-->" prompt. If your machine has some sort of graphics
- capability you can try the graphics demo as follows. Type "(load
- 'turtle)" without the "'s. Wait until you see the "t" and the
- prompt "-->" again, then type "(GraphicsDemo)". You should see
- some Logo like squirals etc. If you do not have any graphics
- capability try "(load 'queens)" or "(load 'hanoi)" and then
- (queens 5) or (hanoi 5) respectively. For a more extensive
- example turn to the last couple of chapters in LISPcraft and look
- at the deductive data base retriever. Type (load 'match) and look
- at the match.l documentation. You can then play with all the
- funcions mentioned in LISPcraft.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 3
-
-
-
- EXAMPLE LOAD FILES AND THE PC-LISP.L FILE
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Included with PC-LISP (V2.11) are a number of .L files.
- These include: PC-LISP.L, MATCH.L, TURTLE.L, DRAGON.L and perhaps
- a few others. These are as follows.
-
- PC-LISP.L
- ~~~~~~~~~
- A file of extra functions to help fill the gap between PC
- and Franz LISP. This file defines the pretty print function and a
- number of macros etc. It will be automatically loaded from the
- current directory or from the directory whose path is set in
- LISP%LIB when PC-LISP is executed. The functions in this file are
- NOT documented in this manual, look instead at a Franz manual.
-
- MATCH.L
- ~~~~~~~
- A small programming example taken from the last 2 chapters
- of LISPcraft. It is a deductive data base retriever. This is
- along the lines of PROLOG. Very few changes were necessary to get
- this to run under PC-LISP.
-
- TURTLE.L
- ~~~~~~~~
- Turtle Graphics primitives and a small demonstration
- program. To run the demo you call the function "GraphicsDemo"
- without any parameters. This should run albeit slowly on just
- about every MS-DOS machine. Note that the video functions that
- are still experimental so use them for fun but don't rely on
- them. These primitives look at the global variable !Mode to
- decide what resolution to use. If you have mode 8 (640X400) you
- should use it as the lines are much sharper. Turtle graphic modes
- can be set by typing (setq !Mode -number-).
-
- DRAGON.L
- ~~~~~~~~
- A very slow example of a dragon curve. This one was
- translated from a FORTH example in the April/86 BYTE. It takes a
- long time on my 8Mhz 80186 machine so it will probably run for a
- few hours on a PC or AT. I usually let it run for about 1/2 hour
- before getting tired of waiting. To run it you just type (load
- 'dragon) then type (DragonCurve 16). If you have a higher
- resolution machine like a Tandy 2000 then type (setq !Mode 8)
- before you run it and it will look sharper at this (640x400)
- resolution.
-
-
-
-
-
-
-
-
-
-
-
-
- 4
-
-
-
- USERS GUIDE
- ~~~~~~~~~~~
- The PC-LISP program is self contained. To run it just type
- the command PC-LISP or whatever you called it. When it starts it
- will start grabbing memory in chunks of 16K each. By default PC-
- LISP will grab as much memory as possible but by setting the
- LISP%MEM environment variable to an integer >= 3, PC-LISP will
- stop when this many 16K blocks have been allocated. These will be
- distributed to the three basic data types in percentages that you
- can specify via 2 environment variables. The default is that 5%
- of the memory will be allocated for alpha atoms. 5% will be
- allocated for heap space, and the rest for cons,port, fixnum,
- string, flonum and hunk cell types.If you set the environment
- variables LISP%HEAP and LISP%ALPH to an integer between 1 and 85
- these will become the new percentages for the heap and alpha
- respectively, the rest going to cons, port,flonum, fixnum, hunk
- and string cells. Note that the percentages are only accurate to
- the nearest 16K boundary. In other words the set of 16K blocks
- are divided among the three types as closely to the percentages
- that you specify as possible. If the percentages that you specify
- are unreasonable PC-LISP will stop with an error message,
- otherwise PC-LISP will continue by giving back a very small
- amount of memory for use by the standard I/O routines. You can
- alter the amount given back by setting the environment variable
- LISP%KEEP to the amount you want to give back (See memory
- management). PC-LISP will then print the banner message, the
- total memory available and the actual percentages that are
- allocated to each object. Before processing the command line PC-
- LISP will look for a file called PC-LISP.L first in the current
- directory, next in the library directories specified in the
- LISP%LIB environment variable as per the (load) function. If it
- finds PC-LISP.L it will be loaded. Next PC-LISP will read the
- parameters on the command line. The usage is as follows.
- *
- PC-LISP [=nnnn] [file]
-
- The optional parameter =nnnn is the Lattice set stack size
- option. It is preset to 32K and cannot be set smaller. You may
- set it larger up to 64K if you wish. A 32K stack gives you about
- 466 recursive calls, 50K = 731 calls, 60K = 878 calls, and 64K =
- 936 calls. 8086 machines do not allow effecient stacks > 64K.
-
- The files on the command line are processed one by one. This
- consists of loading each file as per the (load) function. This
- means that PC-LISP will look in the current directory for file,
- then in file.l, then in the directories given in the LISP%LIB
- environment variable, when found the file is read and every list
- is evaluated. The results are NOT echoed to the console. Finally
- when all the files have been processed you will find yourself
- with the LISP top level prompt '-->'. Typing control-Z and ENTER
- (MS-DOS end of file) when you see the '-->' prompt will cause PC-
- LISP to exit to whatever program called it. If an error occurs
- you will see the prompt 'er>'. For more info see the 'TERMINATION
- OF EVALUATION' section of this manual and the commands
- (showstack), (trace), and (untrace).
-
-
- 5
-
-
-
- SYNTAX OR WHAT IS A LIST ANYWAY?
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- You will now be in the LISP interpreter and can start to
- play with it. Basically it is expecting you to type an S-
- expression whose value it will evaluate and return. Formally an
- S-expression can be defined with a B.N.F Grammar where + means at
- least one occurence of and, * means any number of occurences of.
-
-
- <S-expression> ::= <fixnum> | <flonum> | <string> | <symbol>
- | '(' <elements> ')'
-
- +
- <elements> ::= (<S-expression>) '.' <S-expression>
- *
- | (<S-expression>)
-
-
- Where characters whose ascii values are in 0..31 are ignored
- and have no effect other than delimiting other input items. Also
- characters between ; and the end of a line are ignored in the
- same way as the white space characters just described, these are
- used to introduce comments into your LISP programs.
-
- The the basic list elements <fixnum>, <flonum>, <string> and
- <symbol> are defined as follows.
-
- A <fixnum> is a sign + , - or none followed by a sequence of
- digits 0..9. If the sequence of digits represents a fixnum larger
- than can be stored in a 32 bit integer it is taken to be the
- nearest <flonum>. A <fixnum> can always be spotted when it is
- printed by the lack of a radix point. Examples are: 2, +2, -2,
- and -333333 .
-
- A <flonum> is a sign + , - or none followed by digits 0..9
- which may be followed by a radix point and more digits 0..9 this
- may optionally be followed by an exponent specifier 'e' or 'E'
- which may optionally be followed by a sign + , - or none,
- optionally followed by the exponent digits 0..9. A <flonum> can
- always be spotted when it is printed by the presence of either a
- radix point, or the exponent specifier 'e'. Examples : 2.0,
- -2.0, +2.0, -2e10, -2e+20, -4.0E-13, 2E, -2E
-
- A <string> is a " followed by up to 254 characters followed
- by a terminating " or |. If the character \ is present in the
- string and the following character is one of t,b,n,r or f the two
- characters are replaced by a tab, backspace, newline, carriage
- return or form feed respectively. If the \ is not followed by one
- of the previously mentioned special characters, the following
- character is used to subtitute the \ and itself in the string.
- The \ is called the escape character and allows you to put non
- printing formatting characters into a string. It also allows you
- to put a " or | into a string which you could not
- otherwise do. Examples: "abcd", "a\tb", "a\"b", "a\|b"
-
-
- 6
-
-
-
- SYNTAX OR WHAT IS A LIST ANYWAY? CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- A <symbol> is either a string delimited with |'s instead of
- the "'s, or a sequence of characters none of which are spaces or
- non printing characters with ascii values < 32 or > 126. If the
- symbol is delimited with |'s the escape character \ may be used
- in exactly the same manner as with a string and all characters
- may be placed between the | delimiters with the exception of " or
- | which must be preceeded by the escape character if they are to
- be literally included in the symbol. If the symbol is not
- delimited by |'s then the characters must be in a sequence that
- follows the following rules. The characters ( ) [ ] " | and ; are
- reserved and will cause termination of the symbol. The set of
- characters that are skipped as white space (those with ascii
- values in the range 0..31) are termed white space characters. The
- set of characters that have been defined as read macros are
- termed macro trigger characters. Only the ' char is initially a
- read macro trigger character. The special characters are all of
- these above character classes. Using these definitions, a symbol
- can either start with a character in 0..9 or a character not in
- 0..9. If the character is not in 0..9 then the the following
- characters can be chosen from among all but the special
- characters. If the first character in the symbol is in 0..9 then
- the last character must be chosen from among the set of all
- characters that are neither special nor in 0..9. A symbol may
- be composed of up to 254 characters all of which are significant.
- Here are a few examples: a a1 1a 1- 1234abc #hi# !hi% An_ATOM
- |ab\nc| junk.l ThisIsOneRatherLargeAtomThatDemonstratesLength.
-
- An atomic S-expression is just one of a fixnum, flonum,
- string and symbol. The only other type of S-expression is a list
- S-expression.
-
- In order to describe what a list S-expression is you need to
- know some lisp terminology for the parts of a list. First a list
- consists of two parts, the first element of the list is called
- the car of the list and the rest of the elements in the list is
- called the cdr of the list. Don't blame me I did not pick these
- names, they come from register names on an old IBM machine. For
- example the list (a b c) has car a and cdr (b c). Now that we
- know the two parts of a list, we need to know how to build a
- list. A list is built with a cons or constructor cell. The
- constructor cell has two parts to it, the first is the car of the
- list and the second is the cdr of the list. Hence one cons cell
- describes one list. Its car part describes the first element in
- the list, and its cdr part describes the list of the rest of the
- elements in the list. For the example list (a b c), the internal
- structure may look something like this, where a [ | ] represents
- a cons cell *--> is a pointer, / is a nil pointer.
-
- [*|*] ---> [*|*] ---> [*|/]
- | | |
- v v v
- a b c
-
-
-
- 7
-
-
-
- SYNTAX OR WHAT IS A LIST ANYWAY? CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Here is an example of a simple nested list which can be
- input as : (a (b c) nil d) and which results in a structure like
- this:
-
- [*|*] ---> [*|*] ---> [/|*] ---> [*|/]
- | | |
- v v v
- a [*|*] ---> [*|*] d
- | |
- v v
- b c
-
- The dot '.' can be used to separate the last element in a
- list from the others in the list. When this occurs the
- constructed list will have a slightly different last cons cell
- second field. Rather than pointing to another cons cell whose car
- points to the last element, this field will point directly to the
- last element. For example inputting (a . b) creates the following
- list structure, which will also print as (a . b).
-
- [*|*]
- | |
- v v
- a b
-
- However if the last element in the list is another list and
- we preceed it by a dot, the list is spliced into the upper list
- as if the last element were not really a list. For example if I
- were to input (a . (b . (c))) the following structure which is
- identical to that constructed by (a b c) would be built. It will
- also print as (a b c).
-
- [*|*] ---> [*|*] ---> [*|/]
- | | |
- v v v
- a b c
-
-
- The dotted pair is not normally used except when you wish to
- save storage. An example might be when you create a list of
- symbols and their associated values. In this case making the
- symbol and its associated value a dotted pair will save 1 cons
- cell or about 10 bytes per symbol value pair.
-
- Finally, I have shown these structures with symbol elements.
- You can have absolutly any type as an element of a list,
- including of course a list as shown in the second example above.
- This is a very quick look at list structure and you should look
- at LISPcraft for more details.
-
-
-
-
-
- 8
-
-
-
- META SYNTAX
- ~~~~~~~~~~~
- Following are some syntactic properties that are really
- above the level of the syntax of a simple S-expression. Thus they
- are called meta syntax conventions. I consider Meta syntax as
- anything that does not conform to the B.N.F grammar previously
- given. These extensions to the syntax of S-expressions consist of
- any extra syntax intdoduced by built in or user defined read
- macros and the replacement of multiple parenthesis which occurs
- when a single super parenthesis is used.
-
- PC-LISP supplies one built in read macro called 'quote' and
- written using the little ' symbol. This read macro is just a
- short hand way of writing the list (quote S). Where S is the S-
- expression that follows the ' in the input stream. Here are some
- examples of the simple conversion that the read macro performs on
- your input.
-
- 'apples -- goes to --> (quote apples)
- '|too late| (quote |too late|)
- '(1 2 3) (quote (1 2 3))
- ''a (quote (quote a))
- '"hi" (quote "hi")
-
- If you are new to LISP you will soon see just how useful
- this little read macro is when you start typing expressions. It
- reduces the amount of typing you must do, reduces the amount of
- list nesting you have to look at and draws attention to data in
- your expressions.
-
- User defined read macros are also provided. See the
- (setsyntax) function in the next section of the manual. The
- backquote macro together with comma (,) and at (@) are
- implemented in the PC-LISP.L load file, but are not documented
- here. Again, see LISPcraft for a discussion of these read macros.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 9
-
-
-
- META SYNTAX CONT'D
- ~~~~~~~~~~~~~~~~~~
-
- PC-LISP also provides the meta or super parenthesis [ ].
- One of the problems with LISP is the often overwhelming number of
- parenthesis. It is very common to not supply enough closing )'s
- and therefore have syntactic/semantic errors in your program. The
- [ and ] characters when properly used allow you to force certain
- structures even if enough )'s have not been provided. They
- operate as follows. When the [ is encountered in the input, it
- acts like a ( except that a note is made of the number of
- unclosed ('s so far. Now when a ] is encountered in the input,
- all lists up to and including the matching [ are closed. If there
- is no matching [, ie none has been entered or all have been
- closed with a ] then all open lists are closed. These parenthesis
- may be nested up to 16 levels deep. But, deep nesting reduces
- their usefullness. NOTE: If you open a list with a [ you must
- close it with a ]. If you close it with a ) you will cause the
- next [ ] pair to function incorrectly. The super nesting
- information is reset whenever a new file is processed, or
- whenever the break level is entered. That is, meta parenthesis
- cannot be used accross a load or read of another file. Finally,
- here are a few example legal inputs which use the meta
- parenthesis and the list that results from their input.
-
- ((("hello world\n"] -- goes to --> ((("hello world\n")))
- (([(((8 9] 10 ] ((((((8 9)))) 10))
- [[[[[a]]]]] (((((a)))))
-
-
- I should just mention again the fact that meta parenthesis
- will not operate accross multiple reads. For example suppose you
- were using (read) to get sublists from lists in one file, and
- then swithced to reading lists from another file, then returned
- to the original file. If the original input file made use of the
- super parenthesis and the particular sublist being read was
- between a pair of superparenthesis, this information will be lost
- when you resume reading the file. Hence the next ] you hit will
- terminate all open lists rather than those opened after the lost
- [. The moral of this example is not to use the super parenthesis
- in a data file whose reading may be interrupted by other I/O.
- This is not a particularly imposing limitation.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 10
-
-
-
- SYNTAX ERRORS
- ~~~~~~~~~~~~~
- When you enter a list which is not correct syntactically
- the interpreter will return the wonderfully informative 'syntax
- error' message. This message will either contain a further
- message describing the error, or contain the text of the nearest
- token to the error. You will have to figure out where it is in
- the input list. Note that if you do not finish entering a list,
- ie you put one too few closing )'s on the end, the interpreter
- will wait until you enter it before continuing. If you are not
- sure what has happened just type "]]" and all lists will be
- closed and the interpreter will try to do something with the
- list. If you are running input from a file the interpreter will
- detect the end of file and give you a 'syntax error' because the
- list was unclosed. Try also (showstack), it can help pinpoint the
- error in a large load file. V2.11's syntax error handling is
- pretty poor. Hopefully I can improve it in later versions
- (suggestions are welcome).
-
- EVALUATING S-EXPRESSIONS
- ~~~~~~~~~~~~~~~~~~~~~~~~
- The interpreter expects an S-expression to be typed at the
- prompt '-->'. The interpreter will evaluate the expression and
- print the resulting S-expression. If the expression is either a
- fixnum or a flonum, the interpreter just returns it because a
- number evaluates to itself. If the expression is a string, the
- interpreter also returns it because a string evaluates to itself.
- If however the expression is a symbol, the interpreter returns
- the binding of the symbol. It is an error to try to evaluate a
- symbol that has no binding. Certain predefined atoms are
- prebound, while all other symbols are unbound until bound by a
- function call or a set / setq. If the expression is a list, then
- the first element in the list is taken to be a function name or
- description, the rest of the elements are taken to be parameters
- to the function. The interpreter will evaluate each of the
- arguments and then pass them to the appropriate function whose
- result is returned. For example: The list S-expression with a '+'
- as the first element and fixnums as elements will evaluate as the
- sum of the fixnums. Eg.
-
- -->(+ 2 4 6 8)
- 20
-
- We can also compose these function calls by using list
- nesting. Sublists are evaluated prior to upper levels. Eg:
-
- -->(- (+ 6 8) (+ 2 4))
- 8
-
- We can also perform operations on other objects besides
- numbers. Suppose that we wanted to reverse the list (time flies
- like arrows). Trying the built in function reverse we get:
-
- -->(reverse (time flies like arrows))
- --- error in built in function [apply] ---
-
-
- 11
-
-
-
- EVALUATING S-EXPRESSIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- But the interpreter will be confused! It does not know that
- 'time' is data and not a function taking arguments 'flies',
- 'like' and 'arrows'. To indicate it is upset PC-LISP prints out
- the error message above and alters the prompt. More on this
- later. What can we do to fix this? We must use the function
- 'quote' which returns its arguments unevaluated, hence the name
- "quote".
-
- -->(reverse (quote (time flies like arrows)))
- (arrows like flies time)
-
- Will give us the desired result (arrows like flies time). We
- can do the same thing without using the (quote) function
- directly. Remember the read macro ' above? Well it will replace
- the entry '(time flies like arrows) with (quote(time flies like
- arrows)). So more concisely we can ask PC-LISP to evaluate:
-
- -->(reverse '(time flies like arrows))
- (arrows like flies time)
-
- This gives us the correct result without as much typing. You
- will now note that the subtraction of 2+4 from 6+8 could also
- have been entered as:
-
- -->(- (+ '6 '8) (+ '2 '4))
- 8
-
- However, the extra 's are redundant because a fixnum
- evaluates to itself. In general a LISP expression is evaluated by
- first evaluating each of its arguments, and then applying the
- function to the arguments, where the function is the first thing
- in the list. Remember that evaluation of the function (quote s1)
- returns s1 unevaluated. LISP will also allow the function name
- to be replaced by a function body called a lambda expression.
- Which is just a function body without a name. Example:
-
- -->((lambda(x)(+ x 10)) 14)
- 24
-
- Which would be processed as follows. First the parameters to
- the lambda expression are evaluated. That's just 14. Next the
- body of the lambda expression is evaluated but with the value 14
- bound to the formal parameter given in the lambda expression. So
- the body evaluated is (+ x 10) where x is bound to 14. The result
- is just 24. Note that lambda expressions can be passed as
- parameters as can built in functions or user defined functions.
- Hence I can evaluate the following input. Note I use the ]
- character to close the three open lists rather than typing ))) at
- the end of the line.
-
- -->((lambda(f x)(f (car x))) '(lambda(l)(car l)) '((hi]
- hi
-
-
-
- 12
-
-
-
- EVALUATING S-EXPRESSIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Which evaluates as follows. The parameters to the call which
- are the expressions '(lambda(l)(cdr l)) and '((hi)) are
- evaluated. This results in the expressions being returned because
- they are quoted. These are then bound to 'f and 'x respectively
- and the body of the first lambda expression is evaluated. This
- means that the expression ((lambda(l)(car l))(car ((hi)))) is
- evaluated. So again the parameters to the function are evaluated.
- Since the only parameter is (car ((hi))) it is evaluated
- resulting in (hi). This is then bound to l and (car l) is
- evaluated giving hi.
-
- PC-LISP is also capable of handling all other function body
- kinds. These are lambda, nlambda, lexpr, fexpr and macro kinds.
- These expression kinds may all have multiple bodies which are
- evaluated in order, the last one producing the value that is
- returned. See the section on BUILT IN FUNCTIONS and MACROS for
- more details on these kinds and how they operate. Better yet read
- LISPcraft.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 13
-
-
-
- TERMINATION OF EXPRESSION EVALUATION
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- There are three distinct ways that evaluation can terminate.
- First, evaluation can end naturally when there is no more work to
- do. In this case the resulting S-expression is printed on the
- console and you are presented with the prompt "-->". Second, you
- can request premature termination by hitting the CONTROL-BREAK or
- CONTROL-C keys simultaneously (hereafter referred to as CONTROL-
- BREAK). Note that this will only interrupt list evaluation, it
- will NOT interrupt garbage collection which continues to
- completion. So, if you hit CONTROL-BREAK or CONTROL-C and you
- don't get any response, wait a second or two because it will
- respond after garbage collection ends. Finally, execution can
- terminate when PC-LISP detects a bad parameter to a built in
- function, a stack overflows, a division by zero is attempted, or
- an atom is unbound etc. In all cases but a normal termination you
- will be returned to a break error level. This is when the prompt
- looks like 'er>'. This means that variable bindings are being
- held for you to examine. So if the evaluation aborts with the
- message "error in built in function [car]", you can examine the
- atom bindings that were in effect when this error occurred by
- typing the name of the atom desired. This causes its binding to
- be displayed. When you are finished with the break level just hit
- CONTROL-Z plus ENTER and you will be placed back in the normal
- top level and all bindings that were non global will be gone.
- Note you can do anything at the break level that you can do at
- the top level. If further errors occur you will stay in the break
- level and any bindings at the time of the second error will be in
- effect as well as any bindings that were in effect at the
- previous break level. If bindings effecting atoms whose values
- are being held in the first break level are rebound at the second
- break level these first bindings will be hidden by the secondary
- bindings.
-
- An error in built in functions 'eval' or 'apply' can mean
- two things. First, your expression could contain a bad direct
- call to eval or apply. Or, your code may be trying to apply a
- function that does not exist to a list of parameters, or trying
- to apply a bad lambda form. The interpreter does not distinguish
- an error made in a direct call by you to eval/apply or an
- indirect call to eval/apply, made by the interpreter on your
- behalf to get the expression evaluated.
-
- It is also useful to know what the circumstances of the
- failure were. You can display the last 20 evaluations with the
- command (showstack). This will print the stack from the top to
- the 20th element of the stack. This gives you the path of
- evaluation that lead to the error. For more information on the
- (showstack) command look in the section FUNCTIONS WITH SIDE
- EFFECTS OR THAT ARE EFFECTED BY SYSTEM.
-
- It is possible but hopefully pretty unlikely that the
- interpreter will stop on an internal error. If this happens try
- to duplicate it and let me know so I can fix it.
-
-
-
- 14
-
-
-
- DATA TYPES IN PC-LISP
- ~~~~~~~~~~~~~~~~~~~~~
- PC-LISP has the following data types, 32 bit integers,
- single precision floating point numbers, lists, ports for file
- I/O, alpha atoms, strings and hunks (up to 126 in length just one
- short of Franz!). The (type) function returns these atoms:
-
- fixnum - a 32 bit integer.
-
- flonum - a single precision floating point number.
-
- list - a list of cons cells.
-
- symbol - an alpha atom, with print name up to 254 chars
- which may include spaces tabs etc, but which
- should not include an (ascii 0) character.
- Symbols may have property, bindings and functions
- associated with them. Symbols with same print
- name are the same object.
-
- string - A string of characters up to 254 in length. It
- has nothing else associated with it. Strings
- with same print name are not necessarily the
- same object.
-
- port - A stream that is open for read or write. This
- type can only be created by (fileopen).
-
- hunk - An array of 1 to 126 elements. The elements may
- be of any other type including hunks. Franz
- allows 127, the missing element is due to a space
- saving decision. This type can only be created
- by a call to (hunk) or (makhunk).
-
- Fixnums and flonums are together known as numbers. The read
- function will always read a number as a flonum and then see if it
- can represent it as a fixnum without loss of precision. Hence if
- the number 50000000000 is entered it will be represented as a
- flonum because it exceeds the precision of a fixnum. If a number
- has a decimal point or exponent specifier 'e' or 'E' in it, it is
- assumed to be a flonum even if there are no non zero digits
- following the radix point.
-
- Fixnums and flonums will not appear the same when printed.
- The print function will output a flonum with a radix point and
- perhaps an exponent specifier if it will make the output smaller.
-
- Hunks when printed appear as { e0 e1 e2 .... eN }. They are
- indexed from zero. They cannot be entered, ie there is no read
- mechanism for creating them you must create them with a function
- call. It is possible to implement arrays and vectors using hunks
- although I have not done this yet. See HUNKS.
-
-
-
-
-
- 15
-
-
-
- THE BUILT IN FUNCTIONS AND VARIABLES
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Following is a list of each built in function. I will denote
- the allowed arguments as follows:
-
- - a1...aN are alpha atom parameters, type symbol.
-
- - h1...hN are string or alpha atoms, type string or symbol.
-
- - x1...xN are integer atom parameters, type fixnum (32bits).
-
- - f1...fN are float atom parameters, type flonun.
-
- - n1...nN are number atom parameters, type flonum or fixnum.
-
- - z1...zN are numbers but all are of the same type.
-
- - l1...lN are lists, must be nil or of type list.
-
- - p1...pN are port atom parameters, type port.
-
- - s1...sN are S-expressions (any atom type or list)
-
- - H is a hunk.
-
- Additional Definitions:
- ~~~~~~~~~~~~~~~~~~~~~~~
- "{a|d}+" means any sequence of characters of length greater
- than 0 consisting of a's and d's in any combination. This
- defines the car,cdr,cadr,caar,cadar... function class as
- follows: "c{a|d}+r".
-
- "[ -stuff- ]" indicates that -stuff- is/are optional and if
- not provided a default will be provided for you.
-
- "*-stuff-*" indicates that -stuff- is not evaluated. An
- example of this is the function (quote *s1*) whose single S-
- expression parameter s1 is enclosed in *'s to indicate that quote
- is passed the argument s1 unevaluated.
-
- For the simpler functions I will describe the functions
- using a sort of "if (condition) result1 else result2" notation
- which should be pretty obvious to most people. For functions that
- are a little more complex I will give a short English description
- and perhaps an example. If the example code shows the '-->'
- prompt you should be able to type exactly what follows each
- prompt and get the same responses from PC-LISP. If the example
- does not show a '-->' prompt the example is a code fragment and
- will not necessarily produce the same results shown.
-
-
-
-
-
-
-
- 16
-
-
-
- PREDEFINED GLOBAL VARIABLES (ATOMS)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- A number of atoms are globally prebound by PC-LISP. These
- variables are testable and setable by you but in some cases
- altering the bindings is highly inadvisable. Note that a binding
- can be inadvertantly altered by defining one of these atoms as a
- local or parameter atom to a function or a prog, or directly by
- using 'set' or 'setq'.
-
- "displace-macros" - This atom when non nil will cause macro
- expansion to be follwed by code substitution if such substitution
- is possible. The default value is nil meaning no substitution.
-
- "t" - This atom means 'true', it is bound to itself.
- Various predicates return this to indicate a true condition. You
- should NOT change the binding of this atom, to do so will cause
- PC-LISP to produce incorrect answers.
-
- "nil" - This is not really an atom, it represents the empty
- list (). It is not bound to () but rather equivalent to () in all
- contexts. Any attempt to create a symbol with print name "nil"
- will result in ().
-
- "$ldprint" - Is initially bound to "t". When not bound to
- "nil" this atom causes the printing of the -- [file loaded] --
- message when the function (load file) is executed. When "nil"
- this atom prevents the printing of the above message. This is
- useful when you want to load files silently under program
- control.
-
- "$gcprint" - Is initially bound to "nil". When bound to
- "nil" garbage collection proceeds silently. If bound non "nil"
- then at the end of a garbage collection cycle 4 numbers are
- printed. The first is the number of collection cycles that have
- occured since PC-LISP was started, the second is the percentage
- of cons cells that are in use, the third the percentage of alpha
- cells, and the third the percentage of heap space that is in use.
- These last three numbers are exactly what you get back with a
- call to (memstat).
-
- "$gccount$ - Is initially bound to 0. It increases by one
- every time garbage collection occurs. This number is the same as
- the first number printed when $gcprint is bound non "nil" and
- garbage collection occurs. While you can set $gccount$ to any
- value you want, its global binding will be reset to the correct
- garbage collection cycle count whenever collection finishes.
-
- "piport", "poport", "errport" - Are bound to the standard
- input, standard output and standard error ports respectively. You
- can use these to force patom, princ, print and pp-form to send
- their output to the standard output or error. Or, to force read
- and readc to get their input from the standard input. They are
- initially bound to the keyboard and screen. You can alter their
- bindings if you wish but this is not recommended.
-
-
- 17
-
-
-
- THE MATH FUNCTIONS
- ~~~~~~~~~~~~~~~~~~
- Functions that operate on numbers, fixnums or flonums. Note
- that the arrow --X--> may indicate what type is returned. If X is
- 's' then the same type as the parameter(s) selected is returned.
- If X is 'f' then a flonum type is returned. If X is 'x' then a
- fixnum is returned. If X is 'b' then the best type is returned,
- this means that a fixnum is returned if possible. Note that you
- should use fixnums together with "1+, 1- zerop" when ever
- possible because doing so gives nearly a 50% decrease in run time
- for many expressions, especially counted loops or recursion.
-
- TRIG AND MIXED FUNCTIONS
- ~~~~~~~~~~~~~~~~~~~~~~~~
- (abs n1) --s-> absolute value of n1 is returned.
- (acos n1) --f-> arc cosine of n1 is returned.
- (asin n1) --f-> arc sine of n1 is returned.
- (atan n1 n2) --f-> arc tangent of (quotient n1 n2).
- (cos n1) --f-> cosine of n1, n1 is radians
- (exp n1) --f-> returns e to the power n1.
- (expt n1 n2) - b-> n1^n2 via exp&log if n1 or n2 flonum.
- (fact x1) --x-> returns x1! ie x1*(x1-1)*(x1-2)*....1
- (fix n1) --x-> returns nearest fixnum to number n1.
- (float n1) --f-> returns nearest flonum to number n1.
- (log n1) --f-> natural logarithm of n1 (ie base e).
- (log10 n1) --f-> log base 10 of n1 {not present in Franz}
- (lsh x1 x2) --x-> x1 left shifted x2 bits (x2 may be < 0).
- (max n1..nN) --s-> largest of n1...nN or (0 if N = 0)
- (min n1..nN) --s-> smallest of n1..nN or (0 if N = 0)
- (mod x1 x2) --x-> remainder of x1 divided by x2.
- (random [x1])--x-> random fixnum, or random in 0...x1-1.
- (sin n1) --f-> sine of n1, n1 is radians.
- (sqrt n1) --f-> square root of n1.
- (1+ x1) --x-> x1+1.
- (add1 n1) --b-> n1+1 (done with fixnums if n1 is fixnum).
- (1- x1) --x-> x1-1.
- (sub1 n1) --b-> n1-1 (done with fixnums if n1 is fixnum).
-
- BASIC MATH FUNCTIONS
- ~~~~~~~~~~~~~~~~~~~~
- (* x1 ...... ..xN) --x-> x1*x2*x3*.....nN (or 1 if N = 0)
- (times n1 .. ..nN) --b-> n1*n2*n3......nN (or 1 if N = 0)
- (product n1....nN) --b-> Ditto
- (+ x1....... ..xN) --x-> x1+x2+x3+.....xN (or 0 if N = 0)
- (add n1 .......nN) --b-> n1+n2+n3+.....nN (or 0 if N = 0)
- (sum n1 .......nN) --b-> Ditto
- (plus n1.......nN) --b-> Ditto
- (- x1....... ..xN) --x-> x1-x2-x3-.....xN (or 0 if N = 0)
- (diff n1.......nN) --b-> n1-n2-n3-.....nN (or 0 if N = 0)
- (difference....nN) --b-> Ditto
- (/ x1....... ..xN) --x-> x1/x2/x3/.....xN (or 1 if N = 0)
- (quotient n1...nN) --b-> n1/n2/n3/.....xN (or 1 if N = 0)
-
- Note that the Basic functions that operate on numbers will
- return a fixnum if the result can be stored in one.
-
-
- 18
-
-
-
- THE BOOLEAN FUNCTIONS
- ~~~~~~~~~~~~~~~~~~~~~
- These functions all return boolean values. The objects t and
- nil represent true and false respectively. Note however that most
- functions treat a non nil value as being t. t is a predefined
- atom whose binding is t while nil is not a real atom but rather
- a lexical item that is EQUIVALENT to () in all contexts. Hence
- nil and () are legal as both an atom and a list in all functions.
-
- Note when comparing flonums and fixnums you cannot use (eq)
- because they are not identical objects. In Franz (eq 1 1) returns
- t because of a space saving trick. You should not rely on this
- working in other LISPS including PC-LISP.
-
- (alphalessp h1 h2) ---> if (h1 ASCII before h2) t else nil;
- (atom s1) ---> if (s1 not type list) t else nil;
- (and s1 s2 .. sN) ---> if (a1...aN all != nil) t else nil;
- (boundp a1) ---> if (a1 bound) (a1.eval(a1)) else nil;
- (eq s1 s2) ---> if (s1 & s2 same object) t else nil;
- (equal s1 s2) ---> if (s1 has s2's structure) t else nil;
- (evenp n1) ---> if (n1 mod 2 is zero) t else nil;
- (fixp s1) ---> if (s1 of type fixnum) t else nil;
- (floatp s1) ---> if (s1 of type flonum) t else nil;
- (greaterp n1...nN) ---> if (n1>n2>n3...>nN) t else nil;
- (hunkp s1) ---> if (s1 of type hunk) t else nil;
- (lessp n1...nN) ---> if (n1<n2<n3...<nN) t else nil;
- (listp s1) ---> if (s1 of type list) t else nil;
- (minusp n1) ---> if (n1 < 0 or 0.0) t else nil;
- (not s1) ---> if (s1 != nil) nil else t;
- (null s1) ---> Ditto
- (numberp s1) ---> if (s1 is fix of float) t else nil;
- (numbp s1) ---> Ditto.
- (or s1 s2 .. sN) ---> if (any si != nil) t else nil;
- (oddp n1) ---> if (n1 mod2 is non zero) t else nil;
- (plusp n1) ---> if (n1 > 0 or 0.0) t else nil;
- (portp s1) ---> if (s1 of type port) t else nil;
- (zerop n1) ---> if (n1 = 0 or 0.0) t else nil;
- (< z1 z2) ---> if (z1 < z2) t else nil;
- (= z1 z2) ---> if (z1 = z2) t else nil;
- (> z1 z2) ---> if (z1 > z2) t else nil;
-
- Note carefully the difference between (eq) and (equal). One
- checks for identical objects, ie the same object, while the other
- checks for two objects that have the same "structure" and
- identical leaves.
-
- Note that the (and) and (or) functions evaluate their
- arguments one by one until the result is known. Ie, short circuit
- evaluation is performed.
-
- Note that proper choice of fixnums over flonums and proper
- choice of fixnum functions can yield large performance
- improvements. For example (zerop n) is faster than (= 0 n)
- because (zerop) like all functions that take number parameters is
- biased towards fixnums.
-
-
- 19
-
-
-
- LIST & ATOM CREATORS AND SELECTORS
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- These functions will take lists and atoms as parameters and
- return larger or smaller lists or atoms. They have no side
- effects on the LISP system nor are their results affected by
- anything other than the values of the parameters given to them.
- These functions are all nondestructive they do not alter their
- parameters in any way.
-
-
- (append l1..ln) ---> list made by joining all of l1..ln.
- If any of l1..ln is nil they are
- ignored.
-
- (ascii n1) ---> atom with name 'char' where 'char'
- has ordinal value n1:(0 < n1 < 256).
-
- (assoc s1 s2) ---> if s2 is a list of (key.value) pairs
- then assoc --> (key.value) from s2,
- where (equal key a1) is t else nil.
-
- (car l1) ---> first element in l1. If l1 is nil
- car returns nil.
-
- (cdr l1) ---> Everything but the car of l1. If
- l1 is nil cdr returns nil.
-
- (c{a|d}+r l1) ---> performs repeated car or cdr's on
- l1 as given by reverse of {a|d}+.
- Returns nil if it cars or cdrs off
- the end of a list.
-
- (character-index h1 h2) -x-> Returns the index (from 1) of first
- char in h2 in h1. h2 can be a fixnum
- ascii value. Returns nil if none.
-
- (concat h1 .. hN) ---> Forms a new atom by concatenating
- all the strings or atoms. Or nil if
- if N = 0.
-
- (cons s1 s2) ---> list with s1 as 1st elem s2 is rest.
- If s2 is nil the list has one
- element. If s2 is an atom the pair
- print with a dot. (cons 'a 'b) will
- print as (a . b).
-
- (explode h1) ---> list of chars in print name of h1.
- If h1 is nil returns (n i l)
-
- (exploden h1) ---> list of ascii values of chars in h1.
- If h1 is nil returns (110 105 108).
-
- (get_pname h1) ---> String equal to print name of atom
- h1 or same as string h1.
-
-
- 20
-
-
-
- LIST & ATOM CREATORS AND SELECTORS (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- (hunk-to-list H) ---> Returns a list whose elements are
- (eq) to those of hunk H and in the
- same order.
-
- (implode l1) ---> atom with name formed by compressing
- first char of each atoms print name
- in l1. Imploding (n i l) returns
- the empty list nil.
-
- (last l1) ---> returns the last element in l1. If
- l1 is nil it returns nil.
-
- (length l1) -x-> fixnum = to length of list l1.
- The length of nil is 0.
-
- (list s1 s2...sN) ---> a list with elements (s1 s2 ...sN)
- If N = 0 list returns nil.
-
- (member s1 l1) ---> If (s1 (equal) to a top level sub
- list of l1) this sublist, else nil.
-
- (memq s1 l1) ---> If (s1 (eq) to a top level sub list
- of l1) this sublist, else nil.
-
- (nth n1 l1) ---> n1'th element of l1 (indexed from 0)
- like (cad...dr l1) with n1 d's.
-
- (nthcdr n1 l1) ---> returns result of cdr'ing down the
- list n1 times. If n1 < 0 it returns
- (nil l1).
-
- (nthchar h1 n1) ---> n1'th char in the print name of h1
- indexed from 1.
-
- (pairlis l1 l2 l3) ---> l1 is list of atoms. l2 is a list
- of S-expressions. l3 is a list of
- ((a1.s1)....) The result is the
- pairing of atoms in l1 with values
- in l2 with l3 appended (see assoc).
-
- (quote *s1*) ---> exactly s1 unevaled without changes.
-
- (reverse l1) ---> the list l1, reversed at top level.
-
- (type s1) ---> list,flonum,port,symbol, fixnum or
- hunk as determined by the type of
- the parameter s1.
-
-
-
-
-
-
-
- 21
-
-
-
- LIST & ATOM CREATORS AND SELECTORS (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- (sizeof h1)
- ~~~~~~~~~~~
- Will return the number of bytes necessary to store an object
- of type h1. Legal values for h1 are 'list,'symbol,'flonum,
- 'fixnum, 'string , 'hunk and 'port. The size returned is the
- amount of memory used to store the cell, incidental heap space,
- property list space, binding stack space and function body space
- is not counted for types 'symbol, 'string or 'hunk.
-
- (stringp s1)
- ~~~~~~~~~~~~
- Will return t if the S-expression s1 is of type string,
- otherwise it returns nil.
-
- (substring h1 n1 [n2])
- ~~~~~~~~~~~~~~~~~~~~~~
- If n1 is positive substring will return the substring in
- string h1 starting at position n1 (indexed from 1) for n2
- characters or until the end of the string if n2 is not present.
- If n1 is negative the substring starts at |n1| chars from the end
- of the string and continues for n2 characters or to the end of
- the string if n2 is not present. If the range specified is not
- contained within the bounds of the string, nil is returned.
-
- (memusage s1) { not in Franz }
- ~~~~~~~~~~~~~
- Will return the approximate amount of storage that the S-
- expression s1 is occupying in bytes. The printname heap space is
- included in this computation as are file true name atoms. This
- function is not smart, it will count an atom twice if it is
- referenced more than once in the list. The space count does not
- include storage needed for binding stacks, property lists, or
- function bodies that are associated with a particular atom. Hunk
- and string space include the heap space owned by the cell.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 22
-
-
-
- NONINTERNING/INTERNING FUNCTIONS
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Unless otherwise stated in this manual, any function that
- returns an atom will intern it (put it on the oblist). However
- the following functions are not included in the above statement.
- Note also that the list returned by (oblist) is a copy of the
- real oblist. Note carefully that the atoms created by read are
- interned. See a really good LISP manual on this stuff because it
- can be really confusing.
-
- (copysymbol a1 s1)
- ~~~~~~~~~~~~~~~~~~
- Returns an UNINTERNED copy of atom a1. If the flag parameter
- s1 is non nil then the returned atom has property, value, and
- function definitions eq to a1 otherwise its property, value and
- function definitions are nil,undefined, and undefined
- respectively.
-
- (gensym [a1])
- ~~~~~~~~~~~~~
- Returns an UNINTERNED atom whose print name is of the form
- Xnnnnn where X is either 'g' or the print name of a1 (if a1 is
- provided) and nnnnnn is some number such that no interned or
- uninterned atom in the system has the same print name. Note that
- the the existence of a clashing interned or uninterned atom is
- checked before selecting the value of nnnnn.
-
- (intern a1)
- ~~~~~~~~~~~
- Will INTERN a1 on the oblist. If an atom with the same print
- name as a1 is already on the oblist THIS ATOM IS RETURNED,
- otherwise a1 is physically added to the oblist and is returned.
-
- (remob a1)
- ~~~~~~~~~~
- Will return a1 after having physically removed a1 from the
- oblist. Future calls to read will create a new atom with the same
- print name as a1. This can be confusing if a1 had a function
- definition, property, or value assocaited with it.
-
- (maknam l1)
- ~~~~~~~~~~~
- Takes a list of atoms as parameter and returns an UNINTERNED
- atom whose print name is the concatenation of the first character
- in the print names of every atom in the provided list parameter.
- This is the same as (implode) except that implode interns its
- result.
-
- (uconcat a1 a2 ... aN)
- ~~~~~~~~~~~~~~~~~~~~~~
- Returns an UNINTERNED atom whose print name is the
- concatenation of each of the print names of a1...aN. If N=0, or
- if N=1 and a1 is nil, then the empty list nil is returned. Note
- that the empty list nil is neither interned or uninterned because
- it is not really an atom.
-
-
- 23
-
-
-
- FILE I/O FUNCTIONS
- ~~~~~~~~~~~~~~~~~~
- These functions perform simple list/atom and character I/O
- you must be careful when writing lists to files to terminate with
- a new line before closing the file. Otherwise they may cause
- problems for some MS-DOS editors etc. These functions operate on
- type 'port' which is returned by 'fileopen' and which when
- printed is just %file@nn% where 'file' is the name of the
- associated port and nn is the file number 0..(20?). MS-DOS
- imposes limits on the number of open files you can have. This is
- usually more than 16 with no more than 5 to the same file.
-
- (close p1)
- ~~~~~~~~~~
- Closes the port p1 and returns t. Note that you must be
- careful to write a line feed (ascii 10) to the file before
- closing it in some cases. Certain MS-DOS text editors do not like
- files with very large line lengths.
-
- (fileopen h1 h2)
- ~~~~~~~~~~~~~~~~
- Opens file whose name is h1 for mode h2 access. h1 should be
- a file name optionally including a path. h2 should be one of 'r,
- 'w, or 'a meaning read, write or append respecively. The function
- if successful returns a port atom which will print as %file@nn%.
- If the function is not successful nil is returned. Fileopen does
- not look in any but the current directory for a relative path or
- file. Note devices like "con:" are allowed in place of file
- names.
-
- (filepos p1 [x1])
- ~~~~~~~~~~~~~~~~~
- If fixnum parameter x1 is not provided filepos will return
- the current file position where the next read/write operation
- will take place for port p1. If x1 is provided it is interpreted
- as a new position where the next read/write should take place.
- The read/write pointer is seeked accordingly and the value x1 is
- returned if the seek completes successfully. Otherwise nil.
-
- (load h1)
- ~~~~~~~~~
- Will try to find the file whose name is h1 and load it into
- PC-LISP. Loading means reading every list, and evaluating it. The
- results of the evaluation are NOT printed on the console. In
- trying to find the file h1, load uses the following strategy.
- First it looks for file h1 in the current directory, then it
- looks for h1.l in the current directory. Then it gets the value
- of the environment variable LISP%LIB which should be a comma
- separated sequence of MS-DOS paths (exactly the same syntax as
- for PATH). It then repeats the above searching strategy for every
- directory in the path list. For example if I entered this from
- the COMMAND shell:
-
-
-
-
-
- 24
-
-
-
- FILE I/O FUNCTIONS (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- "set LISP%LIB= c:\usr\libs\lisp\bootup ; c:\lisp\work\;"
-
- then ran PC-LISP, it would try to load the file PC-LISP.L first
- from the current directory, then from the two directories on the
- C drive that are specified in the above assignment. Future calls
- to (load h1) will also look for files in the same way. When a
- file has been successfully loaded PC-LISP examines the value of
- atom $ldprint. If this value is non-nil (default is t) PC-LISP
- will print a message saying that the file was loaded
- successfully. If this value is nil then no message is printed. In
- either case if the load is successful a value of t is returned
- and if the load fails a value of nil is returned.
-
- (patom s1 [p1]) & (princ s1 [p1])
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Will cause the S-expression s1 to be printed without
- delimiters or escapes on the output port p1, or on the standard
- output if no p1 parameter is given. Without delimiters means that
- if an atom has a print name that is not legal without the | |
- delimiters or with an escape \, neither will be added when
- printing the list with patom. patom returns s1 while princ
- returns t. Strings will print without quotes or escapes.
-
- (print s1 [p1])
- ~~~~~~~~~~~~~~~
- Will cause the S-expression s1 to be printed with delimiters
- and escapes if necessary on the output port p1, or on the
- standard output if no p1 parameter is given. All atoms that would
- require | | delimiting, strings that require " " delimiting and
- characters that would have to be preceeded by the escape to be
- input, will be printed with the delimiters and any necessary
- escapes. If a character is one of the format characters tab, back
- space, carriage return, line feed or form feed, it will print
- preceeded by the escape as \t \b \r \n or \f respectively. If the
- characters ordinal value is < 32 or > 126 and it is not a format
- character, it will print as \?. Print returns the expression s1.
-
- (read [p1 [s1]])
- ~~~~~~~~~~~~~~~~
- Reads the next S-expression from p1 or from the standard
- input if p1 is not given and returns it. If s1 is given and end
- of file is read the read function will return s1. If s1 is not
- given and end of file is read the read function will return nil.
-
- (readc [p1 [s1]])
- ~~~~~~~~~~~~~~~~~
- Reads the next character from p1 or from the standard input
- if p1 is not given and returns it as an atom with a single
- character name. If s1 is given and end of file is read the readc
- function will return s1. If s1 is not given and end of file is
- read the readc function will return nil.
-
-
-
- 25
-
-
-
- FILE I/O FUNCTIONS (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (sys:unlink h1)
- ~~~~~~~~~~~~~~~
- Will erase the file whose name is the print name of atom h1.
- If the erase is successful a value of 0 is returned. If the erase
- is unsuccessful a value of -1 is returned.
-
- (truename p1)
- ~~~~~~~~~~~~~
- Will return an atom whose print name is the same as the name
- of the file associated with port p1. This is just the same as the
- value printed between the % and @ signs when a port is printed.
-
- (flatsize s1 [x1])
- ~~~~~~~~~~~~~~~~~~
- Returns the number of character positions necessary to print
- s1 using the call (print s1). If x1 is present then flatsize will
- stop computing the output size of s1 as soon as it determines
- that the size is larger than x1. This feature is useful if you
- want to see if something will fit in some small given amount of
- space but not knowing if the list is very big or not.
-
- (flatc s1 [x1])
- ~~~~~~~~~~~~~~~
- Returns the number of character positions necessary to print
- s1 using the call (patom s1). x1 is the same as in flatsize.
-
- (pp-form s1 [ p1 [x1] ] )
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- Causes the expression s1 to be pretty-printed on port p1
- indented by x1 spaces. If p1 is absent the standard output is
- assumed. If x1 is absent an indent of 0 is assumed. If s1
- contains a list such as (prog .... label1 ... label2...) the
- normal indenting will be ignored for label1 & label2 etc. This
- causes the labels to stand out. For example IF the following
- function were present in PC-LISP then I could run pp-form:
-
- -->(pp-form (getd 'character-index-written-in-lisp))
- (lambda (a c)
- (prog (n)
- (setq n 1 a (explode a))
- (cond ((fixp c) (setq c (ascii c))))
- nxt:
- (cond ((null a) (return nil)))
- (cond ((eq (car a) c) (return n)))
- (setq n (1+ n) a (cdr a))
- (go nxt:)))
-
- Note that the PC-LISP.L file contains a definition of pp,
- the LISP general function pretty printer. It makes use of pp-
- form to get its work done. I will not describe it here but it is
- fully described in LISPcraft.
-
-
-
-
- 26
-
-
-
- FUNCTIONS WITH SIDE EFFECTS OR THAT ARE EFFECTED BY SYSTEM
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- These functions will either have an effect on the way the
- system behaves in the future or will give you a result about the
- way the system has behaved in the past and future calls will not
- necessarily give the same results.
-
- (def *a1* *l1*)
- ~~~~~~~~~~~~~~~
- a1 is a function name and l1 is a lambda,nlambda, lexpr or
- macro body. The body is associated with the atom a1 from now on
- and can be used as a user defined function. Def returns a1.
-
- -->(def first (lambda(x)(car x)))
- -->(def llast (lexpr(n)(last (arg n))))
- -->(def myadd (nlambda(l)(eval(cons '+ l))))
- -->(def firstm (macro(l)(cons 'car (cdr l))))
-
- (defun *a1* [*a2*] *s0* *s1* *s2* ....*sN*)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Defun will do the same job as "def" except that it will
- build the expression body for you. a1 is the name of the
- expression that you are defining, a2 is an optional expression
- kind indicator which may be either expr, fexpr or macro. The
- default is expr. These kinds correspond directly to lambda,
- nlambda and macro forms. s0 specifies the formal parameters to
- the expression. Usually this is just a list of symbols. If it is
- a single symbol it is assumed that the symbol is the single
- parameter to an lexpr form and an lexpr form will be constructed
- from the ensuing bodies s1....sn. If it is a list of symbols then
- a lambda, nlambda or macro body will be constructed from the
- bodies s1...sn according to the kind specified by parameter a2.
- For example, these calls to defun do the same job as the above
- calls to def.
-
- -->(defun first(x)(car x))
- -->(defun llast n (last (arg n)))
- -->(defun myadd fexpr(l)(eval(cons '+ l)))
- -->(defun firstm macro(l)(cons 'car (cdr l)))
-
- (exit)
- ~~~~~~
- The LISP interpreter will exit to MSDOS. Depending on how
- big you set LISP%MEM MSDOS may ask for a system disk to reload
- COMMAND.COM. Note that the video mode will be left alone if you
- call exit. But if you leave via CONTROL-Z the video mode will be
- set to 80x25B&W. (Only if you have made a call to (#scrmde#)).
-
- (gc)
- ~~~~
- Starts garbage collection of alpha and cell space. Returns t
-
-
-
-
-
-
- 27
-
-
-
- FUNCTIONS WITH SIDE EFFECTS OR THAT ARE EFFECTED BY SYSTEM
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CONT'D
- ~~~~~~
- (get a1 a2)
- ~~~~~~~~~~~
- Will return the value associated with property key a2 in
- a1's property list. This value will have been set by a previous
- call to (putprop a1 s1 a2). Example:
-
- -->(get 'frank 'lastname)
-
- (getd a1)
- ~~~~~~~~~
- Will return the lambda, nlambda or macro expression that is
- associated with a1 or nil if no such expression is associated
- with a1.
-
- (getenv h1)
- ~~~~~~~~~~~
- Will return an atom whose print name is the string set by
- environment variable h1. For example we can get the PATH variable
- setting by evaluating (getenv 'PATH). Note that these must be in
- upper case because MS-DOS converts the variable names to upper.
-
- (hashtabstat)
- ~~~~~~~~~~~~~
- Will return a list containing 503 fixnums. Each of these
- represents the number of elements in the bucket for that hash
- location in the heap hash table. 503 is the size of the hash
- table. This is not especially useful for you but it gives me a
- way of checking how the hashing function is distributing the
- heap using cells. Heap using cells are symbol, string and hunk.
- The cell itself is allocated from the alpha or other memory
- blocks while its variable length space is allocated from the
- heap. Hence this table contains the oblist plus strings and
- hunks. Note however that unlike symbols, strings and hunks are
- not unique objects.
-
- (memstat) { not present in Franz }
- ~~~~~~~~~
- Returns three fixnums. The first is the percentage of cell
- space that is in use. The second is the percentage of alpha cell
- space and the third is the percentage of heap space in use. When
- any of these reach 100%, garbage collection will occur. Alpha and
- cell space is collected together. Heap space is only collected
- when you run out. After garbage collection you will see these
- three percentages drop. The alpha and cell percentages should
- drop to tell you how much memory is actually in use at that
- moment. The heap space when compacted and gathered will not
- necessarily drop to indicate how much you really have left. This
- is because heap space is gathered in blocks of 16K, not all at
- once as with atoms and cells. So, there will almost certainly be
- more than 20% free heap space in other non compacted blocks even
- if memstat reports 80% of the heap space is in use.
-
-
- 28
-
-
-
- FUNCTIONS WITH SIDE EFFECTS OR THAT ARE EFFECTED BY SYSTEM
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CONT'D
- ~~~~~~
- (oblist)
- ~~~~~~~~
- Returns a list of most known symbols in the system at the
- current moment. Note that if you call oblist and assign the
- result somewhere you will cause every one of those objects to be
- kept by the system. If there are lots of large alpha atoms the
- heap and alpha space will be tied up until you set the assigned
- variable to some other value. Several special internal atoms are
- not placed in the returned list to keep them out of user code.
-
- (plist a1)
- ~~~~~~~~~~
- Will return the property list for atom a1. The property list
- is of the form ((ke1 . value1)(key2 . value2)...(keyn . valuen)).
- Note that plist returns a top level copy of the property list
- because remprop destroys this lists top level structure.
-
- (putd a1 l1)
- ~~~~~~~~~~~~
- Identical to "def" except that the parameters a1 and l1 are
- evaluated. This allows you to write functions that create
- functions and add them to the LISP interpreter.
-
- (putprop a1 s1 a2)
- ~~~~~~~~~~~~~~~~~~
- Adds to the property list of a1 the value s1 associated with
- the property indicator a2. It returns the value of a1. For
- example: (putprop 'Peter 'AshwoodSmith 'lastname)
-
- (remprop a1 a2)
- ~~~~~~~~~~~~~~~
- Removes the property associated with key a2 from the
- property list of atom a1. The top level structure of the property
- list is actually destroyed. It returns the old property list
- starting at the point where the deletion was made.
-
- (set a1 s1)
- ~~~~~~~~~~~
- Will bind a1 to s1 at current scope level or globally if no
- scope exists for a1 yet. Set returns s1.
-
- (setplist a1 l1)
- ~~~~~~~~~~~~~~~~
- Will set the property list of atom a1 to the list l1 where
- the list must be ((keyn.valn)..). It returns this new list l1.
-
- (setq *a1* s1 *a2* s2 ..... *an* sn)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Allows an infinite number of variable and value pairs and it
- does not evaluate the variables a1...an. So (setq a 'val1 b
- 'val2) binds val1 to a and val2 to b. Setq will return sn.
-
-
- 29
-
-
-
- FUNCTIONS WITH SIDE EFFECTS OR THAT ARE EFFECTED BY SYSTEM
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CONT'D
- ~~~~~~
- (setsyntax a1 a2 l1)
- ~~~~~~~~~~~~~~~~~~~~
- Is a way of defining a read expression macro l1 to be
- associated with chracter a1. And invoked in 'vmacro or
- 'vsplicing-macro mode depending on a2. This function allows you
- to alter the way that (read) works. Basically after calling
- setsyntax the expression l1 will be invoked whenever the
- character a1 is found in the input stream and this character is
- not escaped or hidden in a comment or delimiters of some kind.
- For example a macro : that pretty prints the following function
- name could be defined as follows:
-
- -->(setsyntax '|:| 'vmacro '(lambda()(list 'pp (read))))
-
- Then if I typed :pp at the input prompt the character :
- would be read causing the expression (list 'pp (read)) to be
- invoked. This would then read the pp atom and construct the list
- (pp pp) which would then be passed back to the read function
- which would pass it back to the eval loop which will evaluate it
- and pretty print the function pp. Read macro expressions are
- lambda expressions that take no parameters. Any calls to (read)
- must not have any arguments, (read) will know where to read the
- next expression from because of a global binding performed by the
- read macro driver on behalf of the read function.
-
- Splicing macros are also available. Just replace the 'vmacro
- parameter with 'vsplicing-macro. What will happen is that the
- returned list will be spliced into the input expression, rather
- than forming a sublist expression in the current input. This is
- useful if you want to define your own comment delimiters and
- return nil. For example let's define a new comment delimiter say
- the < and > characters.
-
- -->(defun SkipToEnd()
- (cond ((eq (readc) '|>|) nil)
- (t (SkipToEnd))))
- SkipToEnd
- -->(setsyntax '|<| 'vsplicing-macro '(lambda()(SkipToEnd)))
- t
- -->(and t <junk junk junk> t)
- t
-
- What I have done is first write a comment skipping function
- that just reads input character by character until the > is
- found. I then associate the character '<' with a lambda
- expression that calls this skipper. The macro is a splicing macro
- as the last (and t <junk...junk> t) demonstrates. Think about
- what would have happened if the macro were non splicing and I put
- a comment in the (and ....) list. Try it and see, then you will
- know why splicing macros are needed.
-
-
-
- 30
-
-
-
- FUNCTIONS WITH SIDE EFFECTS OR THAT ARE EFFECTED BY SYSTEM
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CONT'D
- ~~~~~~
-
- (trace [*a1* *a2* *a3* ..... *an*])
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Will turn on tracing of the user defined functions a1...an.
- Note that you cannot trace built in functions. If you call trace
- with no parameters it will return a list of all user defined
- functions that have been set for tracing by a previous call to
- trace, otherwise trace returns exactly the list (a1 a2...an)
- after enabling tracing of each of these user defined functions.
- If any of the atoms is not a user defined function trace stops
- and returns an error. All atoms up to the point of error will be
- traced.
-
- (untrace [*a1* *a2* *a3* ..... *an*])
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Will disable tracing of the listed functions which must all
- be user defined. If no parameters are given it disables tracing
- of all functions. Untrace returns a list of all functions whose
- tracing has been disabled. Here is a demonstration of how you can
- use them. The --> is the LISP prompt. This is the sort of
- sequence that you should see on the console. The comments ;...
- were added to tell you what is going on.
-
- -->(defun factorial(n) ; define n! = n * (n-1)!
- (cond ((zerop n) 1)
- (t (* n (factorial (1- n]
-
- factorial
- -->(trace factorial) ; ask LISP to trace n!
- (factorial)
- -->(factorial 5) ; ask LISP for 5!
- <enter> factorial( 5 ) ; entered with parm=5
- <enter> factorial( 4 ) ; " " " 4
- <enter> factorial( 3 ) ; " " " 3
- <enter> factorial( 2 ) ; " " " 2
- <enter> factorial( 1 ) ; " " " 1
- <enter> factorial( 0 ) ; " " " 0
- <EXIT> factorial 1 ; exit 0! = 1
- <EXIT> factorial 1 ; exit 1! = 1
- <EXIT> factorial 2 ; exit 2! = 1
- <EXIT> factorial 6 ; exit 3! = 6
- <EXIT> factorial 24 ; exit 4! = 24
- <EXIT> factorial 120 ; exit 5! = 120
- 120
- -->(untrace factorial) ; ask LISP to shut up
- (factorial)
- -->(factorial 5) ; now it is quiet again.
- 120
- -->
-
-
-
-
- 31
-
-
-
- FUNCTIONS WITH SIDE EFFECTS OR THAT ARE EFFECTED BY SYSTEM
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CONT'D
- ~~~~~~
-
- (showstack)
- ~~~~~~~~~~~
- This function will display a copy of the last 20 eval
- and apply evaluations from the internal stack. The top of the
- internal stack is copied whenever LISP is about to enter the
- break level (prompt 'er>'). This means that if you execute some
- function and it aborts prematurely you can call showstack from
- the break level and see exactly what lead to the error. Whenever
- a new error occurs the old copy of the top 20 elements on the
- internal stack is lost and a new trace is copied for you to
- display via (showstack). This is unlike Franz which allows
- lots of break levels. For example consider this example session
- with PC-LISP which is similar to an example in LISPcraft.
-
- -->(defun foobar(y)(prog(x)(setq x (cons (car 8) y]
- foobar
- -->(foobar '(a b c))
- --- error evaluating built in function [car] ---
- er>x
- ()
- er>y
- (a b c)
- er>(showstack)
-
- [] (car 8)
- [] (car 8)
- [] (cons <**> y)
- [] (setq x <**>)
- [] (prog(x) <**>)
- [] (foobar '(a b c))
-
- t
-
- In this example I declared a function called 'foobar' which
- runs a prog and does a single assignment to x. When I execute it
- with parameter '(a b c). PC-LISP correctly tells me that there
- was an error evaluating the built in function 'car'. I can
- examine the values of x and y and see that x is still set to the
- empty list () that the prog call set it to. y is bound to the
- parameter passed to foobar as expected. Next I called (showstack)
- to see the trace of execution. I see that the top evaluation (car
- 8) is the culprit. The evaluation previous to that is also (car
- 8) but this evaluation was before the arguments had been
- evaluated. Remember that fixnums eval to themselves. The <**>
- symbols in the show stack are just a short hand way of saying
- look at the entry above to see what the <**> should be replaced
- with. This greatly reduces the amount of information that you
- have to look at when you read a stack dump. It also allows you to
- follow the stream of partial evaluations by looking at each <**>
- in turn. Note that infinite recursion leaves a stream of <**>'s.
-
-
- 32
-
-
-
- LIST EVALUATION CONTROL FUNCTIONS
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- These functions are the control flow functions for LISP they
- effect which lists are evaluated and how. They operate on the
- basic LISP function types, descriptions of which follow.
-
- (lambda l1 s1....sn)
- ~~~~~~~~~~~~~~~~~~~~
- This is not a function but it is a list construct which
- can act as a function in any context where a function is legal. A
- lambda expression is a function body. The S-expressions s1..sn
- are expressions that are evaluated in the order s1...sn. The
- result is the evaluation of sn. The atoms in the list l1 are
- called bound variables. They will be bound to values that occur
- on the right of the lambda expression before the S-expressions
- s1..sn are evaluated and unbound after the value of sn is
- returned.
-
- (nlambda l1 s1....sn)
- ~~~~~~~~~~~~~~~~~~~~~
- This is a function body construct similar to lambda but with
- a few major differences. The first is that the list l1 must only
- specify one formal parameter. This will be set to a list of the
- UNEVALUATED parameters that fall on the right of the nlambda
- expression when it is being evaluated. This function allows you
- to write functions with a variable number of parameters and to
- control the evaluation of these parameters. For example we can
- write a function called 'ADDEM that behaves the same way as '+ in
- nearly all contexts as follows:
-
- -->(def ADDEM (nlambda(l)(eval(cons '+ l))))
- or
- -->(defun ADDEM fexpr(l)(eval(cons '+ l)))
-
- Both of which create the same nlambda expression. This
- function will behave as follows when spotted on the left of a
- sequence of parameters 1 2 3 4. First it will not evaluate the
- sequence of parameters 1 2 3 4. Second it makes these into a list
- (1 2 3 4). It then binds 'l to this list and evaluates the
- expression (eval(cons( '+ l))). This expression results in (eval
- (+ 1 2 3 4)). Which is just the desired result 10.
-
- (label a1 (lambda|nlambda l1 s1..sn)) {not in Franz}
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- This acts just like a lambda expression except that the body
- is temporarily bound to the name a1 for evaluation of the body
- s1. This allows recursive calls to the same body. The binding of
- the body to the name a1 will be forgotten as soon as the
- expression s1 terminates the recursion. For example:
-
- (label LastElement (lambda(List)
- (cond ((null (cdr List))(car List))
- (t (LastElement (cdr List))))))
-
-
-
-
- 33
-
-
-
- LIST EVALUATION CONTROL FUNCTIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (lexpr (a1) s1 s2 .... sN)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- This function body form is similar to the nlambda form
- except that all of its variable number of arguments are evaluated
- and the args are accessed in a different manner. The second
- element of the lexpr form must be a list of exactly one atom. The
- remaining elements of the lexpr form represent bodies that are
- evaluated one after the other. The result of evaluating a list
- whose first element is an lexpr is just the value that results
- from evaluating s1....sN in order in the context where a1 is
- bound to the number of actual parameters, and the (arg), (setarg)
- and (listify) functions behave as follows:
-
- (arg [n1])
- ~~~~~~~~~~
- When in the context of an lexprs' evaluation, will return
- either the number of arguments provided to the nearest enclosing
- lexpr, or the nth argument indexed from 1 passed to that lexpr
- depending on whether n1 is provided or not as a parameter. An
- error occurs if n1 is less than 1 or greater than (arg).
-
- (setarg n1 s1)
- ~~~~~~~~~~~~~~
- When in the context of an lexprs' evaluation, will return
- exactly s1. It has the side effect that future calls to (arg n1)
- will return the value s1 for the duration of the current
- enclosing lexpr evaluation. An error occurs if n1 is less than 1
- or greater than (arg).
-
- (listify n1)
- ~~~~~~~~~~~~
- When in the context of an lexprs' evaluation, will return a
- tail of the list of arguments that were passed to the nearest
- enclosing lexpr. The head of this tail is either (arg n1) if n1
- is positive, or (arg (+ (arg) n1 1)) if n is negative. An error
- occurs if the value of n1 does not correctly index a head within
- the actual argument list of the nearest enclosing lexpr.
-
- Here is a small lexpr example which just sets some global
- variables to allow us to see what went on inside. Again see
- LISPcraft for a much better description.
-
- -->((lexpr(n)
- (setq a0 n a1 (arg 1) an (arg(arg)))
- (listify -3)
- ) 'A 'B 'C 'D 'E 'F 'G )
- (E F G)
- -->a0
- 7
- -->a1
- A
- -->an
- G
-
-
- 34
-
-
-
- LIST EVALUATION CONTROL FUNCTIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (apply s1 l1)
- ~~~~~~~~~~~~~
- The function s1 is evaluated in the context resulting from
- binding its formal parameters to the values in l1. The result of
- this evaluation is returned. Example:
-
- -->(apply '(lambda(x y z)(* (+ x y) z)) '(2 3 4))
- 20
-
- (cond l1 l2 ... ln)
- ~~~~~~~~~~~~~~~~~~~
- The lists l1 ... ln are checked on by one. They are of the
- form (s1 s2 .. sn). Cond evaluates the s1's one by one until it
- finds one that does not eval to nil. It then evaluates the s2..sn
- expressions one by one and returns the result of evaluating sn.
- If all of the s1's (called guards) evaluate to nil, it returns
- 'nil. For example:
-
- -->(cond ((equal '(a b c) (cdr '(x a b c))) 'yes)
- (t 'opps))
- yes
-
- (eval s1)
- ~~~~~~~~~
- Runs the LISP interpreter on the S-expression s1. It just
- removes a quote from the expression s1. For example:
-
- -->(eval '(+ 2 4))
- 6
-
- (mapcar s1 l1 l2 l3 .... ln)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- This function will map the function s1 onto the parameter
- list made by taking the car of each of l1...ln. It forms a list
- of the results of the repeated application of s1 to the next
- elements in the lists l1...ln. It stops when the list l1 runs out
- of elements. Note that each of l1...ln should have the same
- number of elements, although this condition is not checked for
- and nil will be substituted if a list runs out of elements before
- the others. Extra elements in any list are ignored. For example:
-
- -->(mapcar '< '(10 20 30) '(11 19 30))
- (t nil nil)
-
- Which returns the results of (< 10 11) (< 20 19) and (< 30
- 30) as the list (t nil nil). Note that s1 could be any built in
- function, user defined function or lambda expression. For
- example:
-
- -->(mapcar 'putprop '(John Fred Bill)
- '(Mary Sue Linda)
- '(mother sister daughter))
- (Mary Sue Linda)
-
-
- 35
-
-
-
- LIST EVALUATION CONTROL FUNCTIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (defun a1 macro l1 s1 s2 ... sn)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Macro is a special body, similar to nlambda except that it
- may causes code replacement when it is evaluated. When a macro is
- encountered the list (name arg1 arg2...) is bound to the
- macro parameter. Name is the name of the macro and arg1..argn are
- the arguments that were provided to it. Then the bodies of the
- macro are evaluated and the expression returned by the last body
- is returned. Then depending on the value of displace-macros and
- the type of the returned S-expression, the returned S-expression
- may destructively replace the peice of code that called it. If
- the value of displace-macros is nil (its default value) or the
- type of the returned S-expression is not one that can be
- replaced, no destructive substitution will occur. Next regardless
- of whether the S-expression was substituted or not, the S-
- expression is evaluated and the value returned. This all sounds
- pretty compex, but in fact it is quite simple, here is an
- example:
-
- -->(defun first-elemet macro(l)(cons 'car (cdr l)))
- first-element
- -->(setq x '(first-element '(a b c)))
- (first-element '(a b c))
- -->(eval x)
- a
- -->x
- (first-element '(a b c))
- -->(setq displace-macros t)
- t
- -->(eval x)
- a
- -->x
- (car '(a b c))
- -->(eval x)
- a
-
- In the example above I have first declared a macro called
- 'first-element' which when run given a list parameter should
- return the first element in the list. I could have done this
- using a lambda expression but this would require parameter
- binding etc every time I execute 'first-element'. Rather, what I
- have chosen to do is to cause (first-element x) to be replaced by
- the code (car x) everywhere it is encountered. Then future
- execution of (first-element x) is just as costly as an execution
- of (car x). Let's examine what I did above. First I declared a
- macro which will take the parameter (first-element -stuff-) and
- construct the code (car -stuff-). I then set x to be an
- expression which when evaluated should give 'a. I then verify
- this by evaluating x, sure enough it is 'a. I then look at the
- code for x which has not changed. Now, I set the global variable
- displace-macros to be non nil. What I should now expect is that
- (eval x) will give the same answer, but with the side effect of
- doing the code substitution so that future passes of the
-
-
- 36
-
-
-
- LIST EVALUATION CONTROL FUNCTIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- expression bound to x will run much faster. This is the whole
- reason for macros, they are not much use if they are expanded
- every time, it is more work than a simple user defined lambda
- expression call. Anyway after running x and looking at its
- definition we can see that the code has indeed been substituted.
- It is worth noting that unless you set displace-macros to be non
- nil all your macros will be expanded every time they are
- encountered. This is probably not what you want. You should set
- displace-macros to be t to cause macros to behave properly. The
- only reason I did not set displace-macros to be t by default is
- that Franz does not.
-
- Note, macros may return any type expression however some
- expressions may not result in code substitution because of
- internal problems with doing the substitution. In particular a
- macro that directly returns an atom, hunk or string will never
- result in code replacement, while a macro that returns a list,
- fixnum, flonum or port can result in code replacement. Since code
- replacement is a physical copying of one cell over another heap
- space owning functions cannot be physically substituted because
- their cells are unique. You should note however that these
- limitations do not occur much in practice since usually a macro
- will return a number or a list. For exampe a quoted atom is ok
- because it is really the list (quote x). In any case PC-LISP
- macros will always return the correct values regardless of
- these substitution limitations.
-
- Macro bodies can function in all contexts that an nlambda
- body can function, however expansion, if it is to occur will only
- happen when a macro is referred to by its atom name which was
- defined by a defun, def or putd call. Using macros in this manner
- does not seem to have any real use though.
-
- (macroexpand s1)
- ~~~~~~~~~~~~~~~~
- This function lets you see what the macro expansion of s1
- looks like prior to evaluation and substitution. This function is
- necessary to help debug macro definitions because otherwise the
- intermediate code is only visible on the showstack and the code
- may not be on the showstack when the error occurs. For example:
-
- -->(macroexpand '(first-element '(a b c)))
- (car '(a b c))
-
-
-
-
-
-
-
-
-
-
-
-
- 37
-
-
-
- LIST EVALUATION CONTROL FUNCTIONS CONT'D
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- (prog l1 s1.....sn)
- ~~~~~~~~~~~~~~~~~~~
- Prog is a way of escaping the pure LISP applicative
- programming environment. It allows you to evaluate a sequence of
- S-expressions one after the other in true imperative style. It
- allows you to use the functions (go..) and (return ..) to perform
- the goto and return functions that imperative languages permit.
- Prog operates as follows: The list l1 which is a list of atom
- names is scanned and each atom is bound to nil at this scope
- level. Next the S-expressions s1..sn are scanned once. If any of
- s1..sn are atoms they are bound to the S-expression that follows
- them. Next we start evaluating lists s1...sn ignoring the atoms
- which are assumed to be labels. If after evaluation an S-
- expression is of the form ($[|return|]$ Z) we unbind all the
- atoms and labels and return the S-expression Z. If after
- evaluation a list is of the form ($[|go|]$ Z) we alter our
- evaluation to start next at Z. The functions (go) and (return)
- will return the above mentioned special forms. If at any time we
- reach sn, and it is not a go or a return, we simply unbind all of
- l1 and the labels in s1...sn and return the result of evaluating
- sn. Note that prog labels must be alpha or literal alpha atoms.
- Also note that the (return) and (go) mechanisms are not the same
- as Franz and will only operate if the special form works its way
- back to the prog. Because of this you are advised to keep the
- calls to go and return within the lexical scope of the prog body
- and to insure that the special form returned is not absorbed by
- some higher level function.
-
- For example:
-
- -->(prog (List SumOfAtoms)
- (setq List (hashtabstat))
- (setq SumOfAtoms 0)
- LOOP (cond ((null List) (return SumOfAtoms)))
- (setq SumOfAtoms (+ (car List) SumOfAtoms))
- (setq List (cdr List))
- (go LOOP)
- )
- 306
-
- This peice of code operates as follows. First it creates two
- local variables. Next it binds the variable List to the list of
- hash bucket totals from the alpha hash table. It then sets a sum
- counter to 0. Next it checks the List variable to see if it is
- nil. If so it returns the Sum Of all the Atoms. Otherwise it adds
- the first fixnum in the list List to the running SumOfAtoms,
- winds in the list List by one, and jumps to LOOP. Note also that
- we can accomplish the same thing as the above prog with the much
- simpler example which follows:
-
- -->(eval (cons '+ (hashtabstat)))
- 306
-
-
- 38
-
-
-
- HUNKS
- ~~~~~
- A hunk is just an array of 1 to 126 elements. The elements
- may be any other type including hunks. With hunks it is possible
- to create self referencial structures (see DANGEROUS FUNCTIONS).
- A Hunks element storage space comes from the heap. Hunks like
- strings and alpha print names are subject to compaction
- relocation and reclaimation.
-
- (hunk s1 s2 .... sN)
- ~~~~~~~~~~~~~~~~~~~~
- Returns a newly created hunk of size N whose elements are
- s1, s2 ... sN in that order. N must be in the range 1 to 126
- inclusive. Note that a hunk is printed like a list but
- surrounded by { }. Ie {s1 s2 ...sN}.
-
- (cxr n1 H)
- ~~~~~~~~~~
- Returns the n1'th element of hunk H indexed from 0. Hence n1
- must be in the range 0 .. (hunksize H)-1.
-
- (hunkp s1)
- ~~~~~~~~~~
- Returns true if s1 is of type hunk, otherwise it returns
- nil. Note this function has also been mentioned with the other
- predicates.
-
- (hunksize H)
- ~~~~~~~~~~~~
- Returns a fixnum whose value is the size of the hunk. This
- value is one larger than the largest index allowed into the hunk
- by both cxr and rplacx. The size of a hunk is fixed at the time
- of its creation and can never change throughout its life.
-
- (makhunk n1) or (makhunk (s1 s2 ...sN))
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The first form returns a nil filled hunk of n1 elements.
- Needless to say, n1 must be between 1 and 126 inclusive. The
- second form is just identical to (hunk s1.....sN).
-
- (rplacx n1 H s1)
- ~~~~~~~~~~~~~~~~
- Returns the hunk H, however as a side effect element n1 of H
- has been made (eq) to s1. In other words H[n1] = s1. Note that
- this function like rplaca and rplacd allows you to create self
- referencial structures.
-
-
-
-
-
-
-
-
-
-
-
- 39
-
-
-
- DANGEROUS FUNCTIONS
- ~~~~~~~~~~~~~~~~~~~
- The following two functions have potentially disasterous
- results if used by unwary or inexperienced LISP programmers. The
- third function is provided to make their use less dangerous.
-
- (rplaca l1 s1)
- ~~~~~~~~~~~~~~
- The cons cell l1 is physically altered so that its car is
- (eq) to s1. That is the car pointer of l1 is set to point to s1.
- The list l1 is returned. (l1 must not be nil).
-
- (rplacd l1 s1)
- ~~~~~~~~~~~~~~
- The cons cell l1 is physically altered so that its cdr is
- (eq) to s1. That is the cdr pointer of l1 is set to point to s1.
- The list l1 is returned. (l1 must not be nil).
-
- (copy s1)
- ~~~~~~~~~
- Returns a structure (equal) to s1 but made with new cons
- cells. Note that only cons cells are copied, strings, atoms,
- hunks etc are not copied.
-
- Warning #1 - altering a cons cell allows you to create
- structures that point (refer) to themselves. While this does not
- cause a problem for the LISP interpreter or garbage collector it
- does mean that many built in functions will either loop around
- the structure infinitely or recurse until a stack overflows.
-
- -->(setq x '(a b c d))
- (a b c d)
- -->(rplaca x x)
- ((((((((((((((((((((((((((((((((((((((((...............
- -- stack overflow --
- er>
-
- Warning #2 - altering a cons cell can cause a million little
- side effects that you did not count on. Consider carefully the
- following example.
-
- -->(defun FooBar(x) (cons x '(b c)))
- FooBar
- -->(setq z (FooBar 'a))
- (a b c)
- -->(rplaca (cdr z) 'GOTCHA!)
- (GOTCAH! c)
- -->(FooBar 'a)
- (a GOTCHA! c)
-
- What happened? The rplaca has modified the list that is a
- constant in FooBar. Lists are not copied unless necessary and
- building the list (a b c) did not require a copy of the constant
- list (b c) to be made. Ie (cdr z) is eq to (b c) in FooBar.
-
-
-
- 40
-
-
-
- MSDOS BIOS CALLS FOR GRAPHICS OUTPUT
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- These functions are still experimental. They do however
- allow you to play with drawing recursive curves etc. They
- all result in an INT 10H. This means that the graphics
- should be portable to most MSDOS machines and should run under
- any windowing environment like Topview or MSwindows. This is why
- they are so slow. Note that they all return 't. They do not check
- to see if the INT call was successful or if you have a graphics
- capability. You can crash your system if you abuse these
- functions.
-
- (#scrline# n1 n2 n3 n4 n5)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Draws a line on the screen connecting (n1,n2) with the point
- (n3,n4) using attribute n5. This function calls the BIOS set dot
- function for each point. Hence it is not very fast.
-
- (#scrmde# n1) {ah=0, al=n1, INT 10H}
- ~~~~~~~~~~~~~
- Sets the video mode to n1. Modes are positive numbers 0.....
- Where (8 and 9) are high resolution for the Tandy2000 and I
- suppose are high resolution modes on other machines that support
- the (640 x 400) or greater graphics resolutions. These are all
- listed in your hardware reference manual but basically they are:
- 0 = 40x25B&W, 1=40x25COL, 2=80x25B&W 3=80x25COL, 4 =320x200COL,
- 5=320x200B&W, 6=640x200B&W, 7=reserved, 8=640x400COL,
- 9=640x400B&W etc...? This is as of DOS 2.11. Also note that the
- AT EGA Graphics Modes should also work with no problem however,
- resolutions greater than 1024x1024 will cause the (#scrline#)
- function to cease to work correctly.
-
- (#scrsap# n1) {ah=5, al=n1, INT 10H}
- ~~~~~~~~~~~~~
- Sets the active video page to n1. n1 should be between 0 and
- 8. This is valid for text modes only. Versions of MSDOS other
- than 2.11 may not support this call.
-
- (#scrspt# bh bl al) {ah=11,bh=bh,bl=bl,al=al,INT 10H}
- ~~~~~~~~~~~~~~~~~~~
- Sets the color palette according to the value in bh. For
- most BIOS compatable machines these are: If bh=0 it sets
- background color bl. If bh=1 it sets the default palette to the
- number 0 or 1 in BL. If bh=2 it sets a single palette entry where
- bl is the palette entry number and al is the color value. See
- your BIOS reference for the color values and additional info.
-
-
-
-
-
-
-
-
-
-
-
- 41
-
-
-
- MSDOS BIOS CALLS FOR GRAPHICS OUTPUT (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- (#scrscp# n1 n2 n3) {ah=2,bh=n1,dh=n2,dl=n3,INT 10H}
- ~~~~~~~~~~~~~~~~~~~
- Sets the cursor position to be in page n1 at row n2 and in
- column n3. Where 0 is the top row and 0 is leftmost col.
-
- (#scrsct# n1 n2) {ah=1,ch=n1,cl=n2,INT 10H}
- ~~~~~~~~~~~~~~~~
- Sets the cursor type to agree with the following: n1 bit
- 5 (0 = blink 1 = steady), bit 6 (0 = visible, 1 = invisible),
- bits 4-0 = start line for cursor within character cell. n2 bits
- 4-0 = end line for cursor within character cell.
-
- (#scrwdot# n1 n2 n3) {ah=12,cx=n1,dx=n2,al=n3,INT 10H}
- ~~~~~~~~~~~~~~~~~~~~
- Write a dot (pixel). The pixel at row n1 and column n2 has
- its color value XORed with the color attribute n3. Since the
- color attributes vary from machine to machine you will have to
- look up the correct values for this parameter in your BIOS guide.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 42
-
-
-
- MSDOS BIOS CALLS FOR DATE AND TIME
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Rather than try to implement the (sys:time) function or the
- (status localtime) call in PC-LISP I have provided access to the
- MS-DOS get date and get time BIOS calls. These are INT 21H
- function numbers 2A and 2C hex respectively. Here is how you get
- at them from PC-LISP.
-
- (#date#)
- ~~~~~~~~
- Returns a list of four fixnums. The first element in this
- list represents the year 1980 means 1980 etc. The second element
- is the month of the year where 1 means January etc. The next
- element in the list represents the day of the month where 1 means
- the first day, etc. The last element in the list represents the
- day of the week where 0 means Sunday etc.
-
- (#time#)
- ~~~~~~~~
- Returns a list of four fixnums. The first element in this
- list represents the hour of the day where 1 means 1AM and 24
- means 12 PM. The next element represents the minutes these are 0
- through 59. The next element represents the seconds, these
- represent hundredths of a second, 0-99.
-
- For example:
-
- -->(append (#date#) (#time#))
- (1986 4 6 0 20 23 22 15)
-
- Means that the date is Sunday April 6th, 1986 and the local
- time is 8:23:22 and 15/100 of a second.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 43
-
-
-
- MEMORY EXHAUSTION
- ~~~~~~~~~~~~~~~~~
- The memory is all used up when you get a message such as
- "LISP cons cells exhausted". Usually when this happens it is
- because you are tying up memory somewhere but do not realize it.
- The most common way to tie up memory is to execute an infinite
- recursion such as (defun looper(n)(looper (+ n 1))). The stack
- will of course overflow and YOUR BINDINGS WILL BE HELD FOR YOU!!
- This means that ALL bindings are held. If you execute the above
- program several times from the break level, 'er>', you will
- eventually run out of CONS cells. They are all in use to hold the
- values n, n+1, n+2,...... to the point of the first stack
- overflow. Then n, n+1,.... to the point of the second overflow
- and so on and so on. Eventually there is no more space left to
- evaluate the function (looper). The solution is simple: If you
- run an infinite recursion by mistake and are placed in the break
- level, use the showstack to figure out where you are. Then use
- the break level to examine variables etc. But before retrying
- anything return to the top level. This will cause the held
- bindings to be dropped and the cells will become reclaimable
- garbage (ie free). Consider the following session with PC-LISP
- V2.11:
-
- -->(defun looper(n)(looper (+ n 1))) ; infinite function
- looper
- -->(looper 0) ; run it from 0
- -- Stack Overflow -- ; all n's saved!
- er>n ; last value of n
- 588
- er>(looper 0) ; another run will
- -- Stack Overflow -- ; save more n's
- er>(looper 0)
- -- Stack Overflow --
- er>(looper 0) ; another run will
- LISP out of cons cells! ; save more n's
- B>
-
- Note that in last (looper 0) call we made from the break
- level was unable to complete because we ran out of memory. When
- this happens PC-LISP gives up and returns to DOS, hence the B>
- prompt. We could have avoided this problem if we had entered a
- CONTROL-Z ENTER sequence at the 'er>' prompt before any further
- calls to (looper 0) were made. This would have freed up all the
- held intermediate bindings of n.
-
- If you find that you are running out of heap space it may be
- because you are keeping too many unused strings,symbols or hunks.
- The easiest way to do this by mistake is the following: (setq x
- (oblist)). The variable x is globally set to the oblist contents.
- Now, all objects that were in the oblist at the time of the call
- will never be freed. The heap space associated with their print
- names will also be unreclaimable. The solution is to be careful
- what you do with copies of the oblist if heap space is in demand.
- Usually heap space is not critical and you need not worry.
-
-
-
- 44
-
-
-
- TECHNICAL INFORMATION
- ~~~~~~~~~~~~~~~~~~~~~
- The interpreter is written using the Lattice C compiler
- version 2.03. It consists of 8 separate modules totaling nearly
- 10,000 lines of C. The modules are: A scanner, parser, memory
- manager, list evaluator and critical functions module, two built
- in functions modules, a library of extra Unix libc functions not
- provided by Lattice C consisting of assembly language routines
- for setjmp(), longjmp() and getenv(), and finally a modified C
- start up assembly language module to provide signal trapping for
- stack overflow and control-break. The program is designed to
- compile without changing more than 2 #defines under UNIX 4.2 and
- sys V. This has been done as has porting to a SUN.
-
- Memory is organized as follows. Alpha cells have fields for
- a shallow stack of bindings, a pointer to heap space for the
- print names, a pointer to any built in or user defined functions,
- and a pointer to any property lists. Alpha cells are the largest
- of all the cells and have their own fixed storage area. Heap
- space which is just the space used for the print names of the
- alpha cells and strings, and the element array for hunks may be
- variable sized blocks of up to 254 bytes long. This is why a hunk
- can have only 126 elements in PC-LISP. The rest of the cells used
- by PC-LISP are all considered as one. This consists of the
- flonum, fixnum, list, string, hunk and port cells. They have
- their own contiguous slice of memory. This means that three
- different contiguous types of memory are required. It is managed
- in the following way. At start up time the percentages of memory
- are read from the default settings or the environment variables
- LISP%HEAP and LISP%ALPH. Next memory is allocated in 16K chunks
- these are the largest contiguous pieces handled by the memory
- manager. If the environment variable LISP%MEM has an integer
- value, this is used as the upper limit on the number of 16K
- chunks to allocate. These are all kept track of in a large vector
- of pointers. After all chunks have been allocated 8K are given
- back for use by the I/O functions. If the environment variable
- LISP%KEEP is set to an integer value that many bytes are given
- back instead of 8K. If file I/O seems to stop working it is
- probably because the standard I/O functions have run out of
- memory, in this case either set LISP%KEEP a bit bigger, or set
- LISP%MEM to a value that does not cause all free memory to be
- allocated. Next groups of these blocks are primed for use by
- alpha,cell, or heap managers. These managers handle the
- distribution and reclamation of memory in their block. The heap
- manager will perform compaction and relocation to get free space.
- The alpha and cell managers will perform mark and gather garbage
- collection to get space. The heap manager may request mark and
- gather collection if there is a real shortage of heap space.
-
- Stack overflow detection is done by intercepting the call to
- the Lattice C stack overflow routine, temporarily resetting the
- stack, and them making a call to my own C stack overflow routine.
- This then longjmps out of the error condition. The Unix version
- handles the error in the same way except that the overflow
- results in a SIGSEGV which then calls the same routine.
-
-
- 45
-
-
-
- TECHNICAL INFORMATION (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Control-BREAK detection is done via periodic testing of the
- status in the evaluator main loop, and the read main loop. When a
- break is detected control is transferred to the break handler
- which prints a message and longjmps back to the mainline code.
- The Unix version will have made a signal call asking that the
- break handler be executed when a user break key is hit. Hence the
- results are the same. CONTROL-C checking is done in the same way
- except that a CONTROL-C will only be spotted on I/O so a looping
- non printing function can only be stopped with CONTROL-BREAK.
- Note that CONTROL-BREAK is INT 1BH and CONTROL-C is INT 23H.
-
- If your machine does not support int 1BH, you can easily
- patch PC-LISP to trap whatever vector you want. To do this just
- start disassembling PC-LISP with DEBUG. The procedures that set
- and reset the int 1BH vector are pretty near the start of the
- program and are very easy to spot. Note that there are a couple
- of other set/reset interrupt vector routines here so do not get
- the wrong one. Look for calls to the MS-DOS set interrupt vector
- routine. If you have trouble doing this drop me a line and I will
- try to help you get it done. There should not be many machines
- for which this patch is necessary because most MS-DOS machines,
- even partially PC compatible, seem to generate an interrupt 1BH
- when CONTROL BREAK is hit.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 46
-
-
-
- KNOWN BUGS OR LACKING FEATURES OF V2.11
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- -It is possible to run out of stack space while garbage
- collecting. When this happens the garbage collection is retried
- once but the error is unrecoverable. You should treat this as a
- stack overflow caused by your program. This can be fixed with a
- link inversion marking phase in the next release of PC-LISP. See
- also the section MEMORY EXHAUSTION for more details on this
- problem. Note that if the stack overflows on the second garbage
- collection retry it gives up and advises you of a probable memory
- corruption.
-
- -Line drawing is not too quick, or too clean. The lines take
- time to draw because they go through the BIOS, they are not very
- clean at certain slopes due to some bugs. But the video graphics
- routines are still experimental so do not rely on them too much.
- You will also note that several other video INT calls are
- missing.
-
- -If too many (load 'file) calls fail you will run out of
- available ports. This is because they are left open. PC-LISP does
- not close open load ports if an error occurs while reading from
- them.
-
- -Two special atoms with rather obscure names should never be
- directly returned manipulated in a prog. These are $[|return|]$
- and $[|go|]$. If you attempt say print these from within a prog,
- the print function will return them and this will confuse the
- heck out of prog which uses them for internal purposes. Because
- of this the (oblist) call does not return them. Thus the only way
- they can get into your code is for you to enter them directly.
- Since this is unlikely and I have warned you the problem should
- not occur.
-
- -You are not prevented from altering the binding of t. This
- means that if you use t as a parameter or set/setq it to
- something other than t you may cause some strange behaviour,
- especially if you bind t to nil by accident.
-
- -Macros are slightly restricted in that only lists, fixnums
- , flonums or ports can be substituted. This is a small difference
- from Franz but one that would require significant performance
- penalties to implement. Since not substituting these types is
- less expensive than implementing substitution would be, I will
- not implement this feature of Franz in a PC environment.
-
- -Explode and Exploden only work on atoms or strings. In Franz
- you can explode anything. For PC-LISP I decided to leave out this
- feature because it complicates the print functions which are
- already pretty messy.
-
-
-
-
-
-
- 47
-
-
-
- KNOWN BUGS OR LACKING FEATURES OF V2.11 (CONT'D)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- -It is possible for the I/O functions to stop working if they
- run out of memory. Since they get their memory separately from
- the other functions in PC-LISP the only solution is to run PC-
- LISP with a little less memory either by setting the environment
- variable LISP%MEM to a value that leaves one or more 16K blocks
- free, or to set LISP%KEEP a little larger than 8K so that more
- memory is free for use by the I/O functions.
-
- -The interpreter is slow. I am planning on introducing a
- compiler which should speed things up significantly. I will also
- rewrite a very small portion of the interpreter in assember which
- should double or tripple the speed.
-
- -Car and cdr will not access the first and second element of
- a hunk as they do in Franz.
-
- -Showstack does not print lists in compressed form
- horizontally. The vertical compression <**> is however done. It
- also occasionally gets confused and does not print the last
- evaluation this sometimes happens on macro expansion. Showstack
- may also get confused and print a list one element at a time
- rather than as a complete list. This is because showstack is
- trying to trace backwards through an internal stack which has a
- lot of intermediate stuff on it and can get confused by the
- extra stacked info.
-
- RE BUGS OR DESIRED ENHANCMENTS
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- I have tried to think of everything that a user could do to
- crash the system and protect him/her from it but I'm sure my
- imagination has only covered half of the possibilities. If you
- find any other bugs or if you think some features would be nice
- to add to PC-LISP, I will consider them for the next major
- release. Please don't hesitate to let me know what you think,
- good or bad. I'd appreciate the feed back as I have put a lot of
- work into this program and want to know what you people out there
- think of it.
-
- Regards,
-
-
- Peter Ashwood-Smith.
-
-
-
-
-
-
-
-
-
-
-
-
- 48
-